/**
 * Project: dx.redisClient
 * 
 * File Created at 2016年4月22日
 * 
 * Copyright 2015-2015 dx.com Croporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * DongXue software Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with dx.com.
 */
package com.dx.redisClient.dao;

import java.util.List;
import java.util.Set;

import com.dx.pf.commons.utils.StringUtil;

import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.ZParams;

/** 
* @ClassName: RedisClusterDaoImpl 
* @Description: Redis集群数据库dao接口实现
* @author wuzhenfang(wzfbj2008@163.com)
* @date 2016年4月22日 下午5:39:55 
* @version V1.0 
*/
public class RedisClusterDaoImpl extends RedisDaoImpl implements IRedisClusterDao{

	public JedisCluster client = null;
	
	public JedisCluster getClient() {
		if(client == null){
			client = (JedisCluster) super.getClient();
		}
		return client;
	}
	
	/**
	 * 将key重命名为newkey，如果key与newkey相同，将返回一个错误。如果newkey已经存在，则值将被覆盖.
	 * @param oldkey：旧键值
	 * @param newkey：新键值
	 * @return
	 */
	public String rename(String oldkey,String newkey){
		if (!StringUtil.isEmpty(oldkey)&& !StringUtil.isEmpty(newkey)) {
			return getClient().rename(oldkey, newkey);
		}else{
			return null;
		}
	}
	
	/**
	 * 一次获取多个key值，如果对应的key不存在则返回null
	 * @param keys
	 * @return
	 */
	public List<String> getMore(String... keys){
		if(keys!= null && keys.length > 0){
			return getClient().mget(keys);
		}else{
			return null;
		}
		
	}
	
	/**
	 * 对应给定的keys到他们相应的values上。
	 * MSET会用新的value替换已经存在的value，就像普通的SET命令一样。
	 * 如果你不想覆盖已经存在的values，请参看命令MSETNX。
	 * MSET是原子的，所以所有给定的keys是一次性set的。
	 * 客户端不可能看到这种一部分keys被更新而另外的没有改变的情况。
	 * @param keys 键值数组
	 * @param values值数组
	 * @return 原子性操作总是OK，因为MSET不会失败
	 */
	public String setMore(String[] keys,String...values){
		if(keys!= null && keys.length > 0 && values!= null && values.length > 0 && keys.length == values.length){
			String[] keysvalues = new String[values.length];
			int index = 0;
			for (String string : values) {
				keysvalues[index] = keys[index] + " " + string;
				index++;
			}
			return getClient().mset(keysvalues);
		}else{
			return null;
		}
	}
	
	/**
	 * 原子性地返回并移除存储在 source 的列表的第一个元素（列表头部），
	 * 并把该元素放入存储在 destination 的列表的最后一个元素位置（列表尾部元素）
	 * @param srckey 源key
	 * @param dstkey 目标key
	 * @return 被移除和放入的元素
	 */
	public String removeListHeadAddOtherListEnd(String srckey, String dstkey) {
		if (!StringUtil.isEmpty(srckey) && !StringUtil.isEmpty(dstkey)) {
			return getClient().rpoplpush(srckey, dstkey);
		} else {
			return null;
		}
	}
	
	/**
	 * 原子性地返回并移除存储在 source 的队列的第一个元素（队列头部），
	 * 并把该元素放入存储在 destination 的队列的最后一个元素位置（队列尾部元素）
	 * @param srckey
	 * @param dstkey
	 * @param timeout
	 * @return 被移除和放入的元素
	 */
	public String popBlockQueuePushOtherQueue(String srckey, String dstkey, int timeout) {
		if (!StringUtil.isEmpty(srckey) && !StringUtil.isEmpty(dstkey)) {
			return getClient().brpoplpush(srckey, dstkey, timeout);
		} else {
			return null;
		}
	}
	
	/**
	 * 是一个阻塞的队列弹出，可以一次弹出多个
	 * @param timeout 超时时间
	 * @param keys 多个key值
	 * @return 其中第一个元素是弹出元素的 key，第二个元素是 value。
	 */
	public List<String> popBlockQueue(int timeout, String... keys) {
		if (keys != null && keys.length > 0) {
			return getClient().brpop(timeout, keys);// brpop
		} else {
			return null;
		}
	}
	
	/**
	 * 是一个阻塞的堆栈弹出，可以一次弹出多个
	 * @param timeout 超时时间
	 * @param keys 多个key值
	 * @return其中第一个元素是弹出元素的 key，第二个元素是 value。
	 */
	public List<String> popBlockStack(int timeout , String... keys){
		if (keys != null && keys.length > 0){
			return getClient().blpop(timeout,keys);
		}else{
			return null;
		}
	}

	/**
	 * 从第一个key对应的set中移除member并添加到第二个对应set中
	 * @param srckey 源key 移除源
	 * @param dstkey 目标key 目标源
	 * @param member 移动的成员
	 * @return 返回移除的数量
	 */
	public long popMemberSetToSet(String srckey, String dstkey, String member) {
		if (!StringUtil.isEmpty(srckey) && !StringUtil.isEmpty(dstkey) && !StringUtil.isEmpty(member)) {
			return getClient().smove(srckey, dstkey, member);
		} else {
			return 0l;
		}
	}
	
	// 差集(difference)
	/**
	 * 返回所有给定key与第一个key的差集,只返回第一个与其他集合不同的元素
	 * @param keys 多个set集合Key数组
	 * @return 只返回第一个与其他集合不同的元素
	 */
	public Set<String> getDiffSets(String... keys) {
		//TODO need to test keys size > 2
		if (keys != null && keys.length > 0) {
			return getClient().sdiff(keys);
		} else {
			return null;
		}
	}

	/**
	 * 返回所有给定key 与第一个key 的差集，并将结果存为另一个dstkey
	 * @param dstkey 目标key
	 * @param keys 比较key的数组
	 * @return 只返回第一个与其他集合不同的元素个数
	 */
	public long getDiffSetsSaveAsSet(String dstkey,String... keys) {
		//TODO need to test keys size > 2
		if (keys != null && keys.length > 0) {
			return getClient().sdiffstore(dstkey, keys);
		} else {
			return 0l;
		}
	}
	
	// 交集(intersection)
	/**
	 * 返回指定所有的集合的成员的交集.
	 * @param keys set键值的数组
	 * @return 返回交集
	 */
	public Set<String> getInterSets(String... keys){
		if (keys != null && keys.length > 0) {
			return getClient().sinter(keys);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回所有给定key 的交集，并将结果存为另一个dstkey
	 * @param dstkey 目标key
	 * @param keys 比较key
	 * @return 返回交集的数量
	 */
	public long getInterSetsSaveAsSet(String dstkey,String... keys){
		if (keys != null && keys.length > 0) {
			return getClient().sinterstore(dstkey, keys);
		} else {
			return 0l;
		}
	}
	
	// 取并集(union)
	/**
	 * 返回给定的多个集合的并集中的所有成员
	 * @param keys
	 * @return 返回并集的数量
	 */
	public Set<String> getUnionSets(String... keys){
		if (keys != null && keys.length > 0) {
			return getClient().sunion(keys);
		} else {
			return null;
		}
	}
	/**
	 * 返回给定的多个集合的并集中的所有成员，并将结果存为另一个dstkey
	 * @param dstkey
	 * @param keys
	 * @return 返回并集的数量
	 */
	public long getUnionSetsSaveAsSet(String dstkey,String... keys){
		if (keys != null && keys.length > 0) {
			return getClient().sunionstore(dstkey, keys);
		} else {
			return 0l;
		}
	}
	
	//zset交集
	/**
	 * 计算numkeys排序按指定键的得出zsets集合的交集，并将结果存储在目的zset中。
	 * 默认情况下，结果中一个元素的分数是有序集合中该元素分数之和
	 * 结果集中的每个元素的分数和输入的有序集合个数相等。
	 * @param dstkey 目标key 如果destination存在，就把它覆盖
	 * @param sets 多个zset集合
	 * @return 结果有序集合destination中元素个数
	 */
	public long getInterScoreSetsSaveAsSet(String dstkey, String... sets) {
		if (!StringUtil.isEmpty(dstkey) && sets != null && sets.length > 0) {
			return getClient().zinterstore(dstkey, sets);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 计算numkeys排序按指定键的得出zsets集合的交集，并将结果存储在目的zset中。
	 * 默认情况下，结果中一个元素的分数是有序集合中该元素分数之和
	 * 结果集中的每个元素的分数和输入的有序集合个数相等。
	 * 使用WEIGHTS选项，你可以为每个给定的有序集指定一个乘法因子，意思就是，
	 * 每个给定有序集的所有成员的score值在传递给聚合函数之前都要先乘以该因子。
	 * 如果WEIGHTS没有给定，默认就是1。
	 * 使用AGGREGATE选项，你可以指定并集的结果集的聚合方式。
	 * 默认使用的参数SUM，可以将所有集合中某个成员的score值之和作为结果集中该成员的score值。
	 * 如果使用参数MIN或者MAX，结果集就是所有集合中元素最小或最大的元素。
	 * @param dstkey 目标key 如果destination存在，就把它覆盖
	 * @param params
	 * 		  SUM: 结果中的元素分数取交集各个集合分数之和
	 *        MIN: 结果中的元素分数取交集各个集合分数最小
	 *        MAX: 结果中的元素分数取交集各个集合分数最大
	 * @param sets 多个zset集合
	 * @return 结果有序集合destination中元素个数
	 */
	public long getInerScoreSetsSaveAsSet(String dstkey, ZParams params, String... sets){
		if (!StringUtil.isEmpty(dstkey) && sets != null && sets.length > 0) {
			return getClient().zinterstore(dstkey, params, sets);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 计算numkeys排序按指定键的得出zsets集合的并集，并将结果存储在目的zset中。
	 * 默认情况下，结果中一个元素的分数是有序集合中该元素分数之和
	 * 结果集中的每个元素的分数和输入的有序集合个数相等。
	 * 使用WEIGHTS选项，你可以为每个给定的有序集指定一个乘法因子，意思就是，
	 * 每个给定有序集的所有成员的score值在传递给聚合函数之前都要先乘以该因子。
	 * 如果WEIGHTS没有给定，默认就是1。
	 * 使用AGGREGATE选项，你可以指定并集的结果集的聚合方式。
	 * 默认使用的参数SUM，可以将所有集合中某个成员的score值之和作为结果集中该成员的score值。
	 * 如果使用参数MIN或者MAX，结果集就是所有集合中元素最小或最大的元素。
	 * @param dstkey
	 * @param sets 多个zset集合
	 * @return 结果有序集合destination中元素个数
	 */
	public long gettUnionScoreSetsSaveAsSet(String dstkey, String... sets){
		if (!StringUtil.isEmpty(dstkey) && sets != null && sets.length > 0) {
			return getClient().zunionstore(dstkey, sets);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 计算numkeys排序按指定键的得出zsets集合的并集，并将结果存储在目的zset中。
	 * 默认情况下，结果中一个元素的分数是有序集合中该元素分数之和
	 * 结果集中的每个元素的分数和输入的有序集合个数相等。
	 * 使用WEIGHTS选项，你可以为每个给定的有序集指定一个乘法因子，意思就是，
	 * 每个给定有序集的所有成员的score值在传递给聚合函数之前都要先乘以该因子。
	 * 如果WEIGHTS没有给定，默认就是1。
	 * 使用AGGREGATE选项，你可以指定并集的结果集的聚合方式。
	 * 默认使用的参数SUM，可以将所有集合中某个成员的score值之和作为结果集中该成员的score值。
	 * 如果使用参数MIN或者MAX，结果集就是所有集合中元素最小或最大的元素。
	 * @param dstkey 目标key 如果destination存在，就把它覆盖
	 * @param params
	 * 		  SUM: 结果中的元素分数取交集各个集合分数之和
	 *        MIN: 结果中的元素分数取交集各个集合分数最小
	 *        MAX: 结果中的元素分数取交集各个集合分数最大
	 * @param sets 多个zset集合
	 * @return 结果有序集合destination中元素个数
	 */
	public long gettUnionScoreSetsSaveAsSet(String dstkey, ZParams params, String... sets){
		if (!StringUtil.isEmpty(dstkey) && sets != null && sets.length > 0) {
			return getClient().zunionstore(dstkey, params, sets);
		} else {
			return 0l;
		}
	}
	
	public void demo(String dstkey){
		 getClient().getClusterNodes();
		 
		 getClient().ping();
		 
		 getClient().select(0);
	}
}
